#pragma once
#include <chrono>
#include <cmath>
#include <cstring>
#include <ctime>
#include <filesystem>
#include <fstream>
#include <iomanip>
#include <iostream>
class InternalBallisticsSimulator {
   public:
    InternalBallisticsSimulator(double timeStep, int outputInterval)
        : m_timeStep(timeStep), m_outputInterval(outputInterval) {}

    //直接传所有参数的构造函数
    InternalBallisticsSimulator(float cylinderLength, float cylinderEffectiveLength,
                                float cylinderInsideDiameter, float springLength, float springOutsideDiameter,
                                float springThickness, float springPreloadLength, float springEffectiveCoils,
                                float pistonMass, float barrelLength, float barrelCaliber, float bulletMass) {
        m_cylinderLength = 0.001 * static_cast<double>(cylinderLength);
        m_cylinderEffectiveLength = 0.001 * static_cast<double>(cylinderEffectiveLength);
        m_cylinderDiameter = 0.001 * static_cast<double>(cylinderInsideDiameter);
        m_springLength = 0.001 * static_cast<double>(springLength);
        m_springDiameter = 0.001 * static_cast<double>(springOutsideDiameter);
        m_springThickness = 0.001 * static_cast<double>(springThickness);
        m_springPreloadLength = 0.001 * static_cast<double>(springPreloadLength);
        m_springEffectiveCoils = static_cast<double>(springEffectiveCoils);
        m_pistonMass = 0.001 * static_cast<double>(pistonMass);
        m_barrelLength = 0.001 * static_cast<double>(barrelLength);
        m_caliber = 0.001 * static_cast<double>(barrelCaliber);
        m_shellMass = 0.001 * static_cast<double>(bulletMass);

        m_cylinderArea = 3.14159 * (m_cylinderDiameter / 2) * (m_cylinderDiameter / 2);
        m_cylinderVolume = m_cylinderArea * m_cylinderLength;
        m_shellarea = 3.14159 * (m_caliber / 2) * (m_caliber / 2);
    }

    double m_timeStep = 0.00001;  //模拟的时间粒度为0.01ms
    int m_outputInterval = 100;    //默认每隔100步输出一次

    //以下为静态量
    double m_springLength;          //弹簧长度
    double m_springDiameter;        //弹簧外径
    double m_springThickness;       //弹簧丝粗细
    double m_springPreloadLength;   //弹簧预压量，
                                    //拍头完全释放时弹簧长度与弹簧原长差值
    double m_springEffectiveCoils;  //弹簧有效圈数
    double m_springStiffness;       //弹簧劲度系数
    double m_springEnergy;          //弹簧储能

    double m_cylinderLength;           //气缸长度，这里与拍头的行程同意
    double m_cylinderEffectiveLength;  //气缸长度，这里与拍头的密封段行程同意
    double m_cylinderDiameter;         //气缸直径，与气缸长度共同决定气缸容积
    double m_cylinderArea;             //气缸底面积
    double m_cylinderVolume;           //气缸容积

    double m_pistonMass;    //拍头质量
    double m_shellMass;     //弹头质量
    double m_barrelLength;  //枪管长度
    int flag = 0;

    double m_caliber = 0.013;                        //口径，默认13mm
    double m_shellarea = 0.0065 * 0.0065 * 3.14159;  //弹头底面积
    double m_atmosphericPressure = 101325;           //大气压强，默认101.325kpa
    double m_pistonDragforce = 3;                    //拍头摩擦阻力，单位为牛顿
    double m_shellDragforce = 2;                     //弹头摩擦阻力，单位为牛顿
    //以下为动态量
    double m_pistonPosition;      //拍头位置，0为完全释放（紧贴推嘴）
    double m_pistonVelocity;      //拍头速度
    double m_pistonAcceleration;  //拍头加速度
    double m_pistonForce;         //拍头受力
    double m_pistonDoneFlag;      //拍头触底标志

    double m_shellPosition;      //弹头位置，0为位于枪管底部（紧贴推嘴）
    double m_shellVelocity;      //弹头速度
    double m_shellAcceleration;  //弹头加速度
    double m_shellForce;         //弹头受力

    double m_airVolume;        //当前气体体积
    double m_airPressure;      //当前气体气压
    double m_airPressureDiff;  //内外压强差

    //函数
    void initializeSpring();
    void initializeCylinder();
    void initializePistonShell();
    void initializeOthers();
    void computeSpring();
    void initialize();
    void initializefromyaml(const std::string& Filepath);
    void initializeall(float cylinderLength, float cylinderEffectiveLength, float cylinderInsideDiameter,
                       float springLength, float springOutsideDiameter, float springThickness,
                       float springPreloadLength, float springEffectiveCoils, float pistonMass,
                       float barrelLength, float barrelCaliber, float bulletMass);

    void stateinitialize();
    void computePressure();
    void computeForces();
    void computeAcceleration();
    void computeVelocity();
    void computePosition();
    std::string outputData(int step);
    std::string computeEfficiency();
    std::string runSim();

    // void outputData();
    double force();
    void runSimulation();
};
